package com.acme.bankapp.domain.bank;

import java.util.Map;

import com.acme.bankapp.domain.exceptions.ClientFeedDataException;
import com.acme.bankapp.domain.exceptions.NotEnoughFundsException;


public class Client implements java.io.Serializable{

	private Account account; // Every client can have (and should have one Account)
	private String firstName;
	private String lastName;
	private Gender gender; // ENUM
	


	public Client(){
		this.account = (Account) new SavingAccount(0);
	}
	
	
	public Client(double startBalance){
		this.account = (Account) new SavingAccount(startBalance);
	}
	
	
	public Client(String fn, String ln, Gender gen, double startBalance){
		this.account = (Account) new SavingAccount(startBalance);
		this.gender = gen;
		this.firstName = fn;
		this.lastName = ln;
	}
	
	
	public Client(String fn, String ln, Gender gen, double startBalance, double overdraft){
		this.account = (Account) new CheckingAccount(startBalance, overdraft); // Only here we will create instance of CheckingAccount. And (cast) it to Account.
		this.gender = gen;
		this.firstName = fn;
		this.lastName = ln;
	}
	
	
	public double getBalance(){
		return this.account.getBalance();
	}
	
	
	public String getClientSalutation(){
		String prefix = this.gender.getPrefix();
		return prefix + " "+this.firstName;
	}
	
	
	public double getMaximumAmountToWithdraw(){
		return this.account.maximumAmountToWithdraw();
	}
	
	
	public void withdraw(double x) throws NotEnoughFundsException{
		if (x >= 0){
			this.account.withdraw(x);
		}
		else{
			throw new NotEnoughFundsException();
		}
	}
	
	
	public void deposit(double x){
		this.account.deposit(x);
	}
	
	
	public String toString() {
		StringBuffer contents = new StringBuffer();
		contents.append("Client:  firstName=" + firstName
				+ ", lastName=" + lastName + ", gender=" + gender);
		contents.append("\n Balance: " + getBalance());
		contents.append("\n Account: " + account);
		contents.append("\n hashCode: " + hashCode());
		return contents.toString();
	}	
	
	
	public static Client createClient(Map<String, String> map) throws ClientFeedDataException{
		String name, gender;
		double balance = 0.0, overdraft = -1.0;
		Client cl = null;
		Gender gen = null;
		if (map.containsKey("balance") && map.containsKey("name") && map.containsKey("gender")){ // required params
			balance = Double.valueOf(map.get("balance"));
			gender = map.get("gender");
			gen = (gender == "m")?Gender.MALE:Gender.FEMALE;
			name = map.get("name");
			if (map.containsKey("overdraft"))
				overdraft = Double.valueOf(map.get("overdraft"));
			if (overdraft == -1.0){ //No overdraft, SavingAccount
				cl = new Client(name, "", gen, balance);
			}else{
				cl = new Client(name, "", gen, balance, overdraft);
			}
			return cl;
		}else{
			throw new ClientFeedDataException();
		}
	}

	
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((firstName == null) ? 0 : firstName.hashCode());
		result = prime * result + ((gender == null) ? 0 : gender.hashCode());
		result = prime * result
				+ ((lastName == null) ? 0 : lastName.hashCode());
		return result;
	}

	
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Client other = (Client) obj;
		if (account == null) {
			if (other.account != null)
				return false;
		} else if (!account.equals(other.account))
			return false;
		if (firstName == null) {
			if (other.firstName != null)
				return false;
		} else if (!firstName.equals(other.firstName))
			return false;
		if (gender != other.gender)
			return false;
		if (lastName == null) {
			if (other.lastName != null)
				return false;
		} else if (!lastName.equals(other.lastName))
			return false;
		return true;
	}
}
